package com.heima.wemedia.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.heima.apis.article.IArticleClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import com.heima.wemedia.service.WmNewsService;
import net.sourceforge.tess4j.TesseractException;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private WmNewsMapper wmNewsMapper;// service 调用service 可能会存在互相引用bug
    @Autowired
    private GreenTextScan greenTextScan;
    @Autowired
    private GreenImageScan greenImageScan;
    @Autowired
    private FileStorageService fileStorageService;
    @Autowired
    private IArticleClient articleClient;// 不要忘记动态代理@EnableFeignClients(basePackages = "com.heima.apis")
    @Autowired
    private WmUserMapper wmUserMapper;
    @Autowired
    private WmChannelMapper wmChannelMapper;
    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;

    /**
     * 自媒体文章审核
     * // 1. 通过ID 查询自媒体 news信息
*    // 2. 审核文本内容
*     // 3. 审核图片信息
*    // 4. 保存文章信息（调用文章API 新增文章article）
*    // 5. OK
     * @param id 自媒体ID
     */
    @Override
    @Async // 异步调用该方法
    public void autoScanWmNews(Integer id) {
        // 1. 通过ID 查询自媒体 news信息
        WmNews wmNews = wmNewsMapper.selectById(id);
        if(wmNews == null) {
            throw new RuntimeException(id+"这个文章不存在");
        }
        // 审核状态要判断

        // 提取图片和文本
        HashMap<String, Object> map = handleTextAndImages(wmNews);

        // 2. 审核文本内容
        // 2.1 自定义的文本审核
//        String text = map.get("contentText").toString();
//        boolean isSensitive = handleSensitiveScan(wmNews, text);
//        if(!isSensitive){
//            return;
//        }
//
//        // 2.2 把这个字符串发送到阿里云进行审核
//        boolean greeTextResult = greeTextContext(wmNews, text);
//        if(!greeTextResult){//greeTextResult = false
//            return;
//        }
//
//
//        // 3. 审核图片信息
//        boolean greeImages = greeImages(wmNews, map);
//        if(!greeImages){//greeImages = false
//            return;
//        }

        // 4. 保存文章信息（调用文章API 新增文章article）
        saveArticle(wmNews);

        // 5. OK  修改自媒体状态 改为审核成功
        updateWmNews(wmNews,(short) 9,"审核成功");

    }

    private boolean handleSensitiveScan(WmNews wmNews, String text) {
        boolean flag = true;

        if(text == null){
            return flag;
        }

        // 从数据库中获取所有敏感词
        List<WmSensitive> sensitives = wmSensitiveMapper.selectList(null);
        List<String> sensitiveList = sensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());

        // 初始化敏感词库 json
        SensitiveWordUtil.initMap(sensitiveList);
        // 比较
        Map<String, Integer> matchWords = SensitiveWordUtil.matchWords(text);
        // 有不合法的词就终止了
        if(matchWords.size() > 0 ){
            updateWmNews(wmNews,(short) 2,"当前文章存在违规内容："+matchWords);
            flag =false;
        }
        return flag;
    }

    /**
     * 保存文章Article
     * @param wmNews
     */
    private void saveArticle(WmNews wmNews) {
        ArticleDto articleDto = new ArticleDto();
        // 基本字段赋值
        BeanUtils.copyProperties(wmNews,articleDto);

        // 用户authorName  authorId
        articleDto.setAuthorId(wmNews.getUserId().longValue());

        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        if(wmNews !=null && wmUser.getName() !=null){
            articleDto.setAuthorName(wmUser.getName());
        }

        // 频道name   channelName
        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
        if(wmChannel !=null && wmChannel.getName() !=null){
            articleDto.setChannelName(wmChannel.getName());
        }

        // layout 布局方式
        articleDto.setLayout(wmNews.getType());
        // 文章标记  flag(前台没有提供，暂时不维护)
        // 创建时间createdTime
        articleDto.setCreatedTime(new Date());
        //wmNews  =  articleId  是一个空的
        ResponseResult responseResult = articleClient.saveArticle(articleDto);
        Long articleId = (Long) responseResult.getData();


        // wmNews  =  articleId的修改
        wmNews.setArticleId(articleId);
        wmNewsMapper.updateById(wmNews);// articleId 附上值了
    }


    @Autowired
    private Tess4jClient tess4jClient;
    /**
     * 图片审核
     * @param wmNews 自媒体对象
     * @param map 包含照片的集合
     * @return   true  审核通过   false  审核失败
     */
    private boolean greeImages(WmNews wmNews, HashMap<String, Object> map) {

        boolean result = true;


        // 获取照片的路径
        List<String> imageUrls = (List<String>) map.get("imageUrls");
        // 没有照片的情况
        if(imageUrls == null || imageUrls.size() == 0){
            return true;
        }

        List<byte[]> images = new ArrayList<>();

        // 照片去重
        imageUrls = imageUrls.stream().distinct().collect(Collectors.toList());
        // 下载照片

        String text ="";

        for (String imageUrl : imageUrls) {
            byte[] bytes = fileStorageService.downLoadFile(imageUrl);
            images.add(bytes);

            try {
                // 图片识别之后文本审核

                // bytes -----> image
                ByteArrayInputStream in = new ByteArrayInputStream(bytes);
                BufferedImage imageFile = ImageIO.read(in);

                // 图片识别文字
                String context = tess4jClient.doOCR(imageFile);
                text = text+ context;

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        if(!text.equals("")){
            boolean isGree = greeTextContext(wmNews, text);
            if(!isGree){// 审核失败了
                return false;// 往下就不走了，省前了
            }
        }

        try {
            // 照片的审核
            Map map1 = greenImageScan.imageScan(images);
            if(map1 !=null){
                // 审核失败
                String suggestion = (String) map1.get("suggestion");
                if(suggestion.equals("block")){
                    // 修改自媒体状态
                    updateWmNews(wmNews,(short) 2,"图片审核不通过");
                    result = false;
                }
                // 不确定信息 需要人工审核
                if(suggestion.equals("review")){
                    // 修改自媒体状态
                    updateWmNews(wmNews,(short) 3,"图片审核不通过");
                    result = false;
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 返回结果
        return result;
    }

    /**
     * 文本内容审核
     * @param wmNews 我们的自媒体
     * @param contentText 需要审核的文本对象
     * @return   true 审核成功   false   审核失败
     */
    private boolean greeTextContext(WmNews wmNews, String contentText) {
        boolean flag = true;

        try {

            if(StringUtils.isBlank(contentText)){
                return flag;//true
            }

            Map map1 = greenTextScan.greeTextScan(contentText);
            if(map1 != null){
                // -审核失败
                String suggestion = (String) map1.get("suggestion");
                if(suggestion.equals("block")){
                    // 修改文章的状态信息
                    updateWmNews(wmNews,(short) 2,"当前文章内容或者标题存在违规内容，请修改后提交");
                    flag= false;
                }

                // -不确定信息，需要人工审核
                if(suggestion.equals("review")){
                    // 修改文章的状态信息
                    updateWmNews(wmNews,(short)3,"当前文章内容或者标题存在不确定内容，请人工审核");
                    flag =false;
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
        }

        // - 审核成功
        return flag;//true
    }

    /**
     * 修改自媒体 状态 审核原因
     * @param wmNews 要修改的自媒体对象
     * @param type  自媒体对象跟踪状态
     * @param msg 失败原因
     */
    private void updateWmNews(WmNews wmNews,short type,String msg) {
        wmNews.setStatus(type);
        wmNews.setReason(msg);
        wmNewsMapper.updateById(wmNews);
    }

    /**
     * 需要的审核的内容的提取
     * @param wmNews 要审核的新闻的信息
     * @return map 要审核的内容的集合
     */
    private HashMap handleTextAndImages(WmNews wmNews) {
        HashMap<String, Object> mapObj = new HashMap<>();

        String contentText = "";// 文本审核
        List<String> imageUrls = new ArrayList<>();// 照片路径集合

        contentText = wmNews.getTitle();// 获取标题
        String content = wmNews.getContent();// 获取内容
        List<Map> maps = JSONArray.parseArray(content, Map.class);
        for (Map map : maps) {
            String type = map.get("type").toString();
            if(type.equals("text")){// 文本
                contentText =contentText + map.get("value");
            }else if(type.equals("image")){// 照片
                imageUrls.add(map.get("value").toString());
            }
        }

        // 把images中的照片路径放到要审核的照片集合中
        String images = wmNews.getImages();// a.png,b.png
        if(StringUtils.isNotBlank(images)){
            String[] images2 = images.split(",");
            imageUrls.addAll(Arrays.asList(images2));//Arrays.asList(images2) 把数组转为集合 addAll把集合添加到集合中
        }

        mapObj.put("contentText",contentText);
        mapObj.put("imageUrls",imageUrls);

        return mapObj;
    }
}
